<?php

namespace app\common\controller;

use think\Db;
use think\Log;

/**
 * 余额操作类
 * Class Balance
 * @package app\common\controller
 */
class Balance
{
	/**
	 * 实例对象
	 * @var object
	 */
	protected static $instance;

	protected $chgTyp = [1, 2];

	protected $typsArr = [1, 2, 3, 9];

	/**
	 * 默认配置
	 * @var array
	 */
	protected $config = [
		"prefix" 		=> "fd_",
		"user" 			=> "user",
		"balance"		=> "balance",
		"log"			=> "balance_log",
		"day_log" 		=> "balance_changes_day"
	];

	/**
	 * 实例化
	 */
	public static function instance()
	{
		if (is_null(self::$instance)) {
			self::$instance = new static();
		}
		return self::$instance;
	}

	/**
	 * 查看 - 是否有余额
	 * @param int $uid 代理ID
	 * @return boolean
	 */
	public function check($uid = 0)
	{
		if (!empty($uid)) {
			$check = Db::name($this->config["balance"])
				->where("main_id = " . $uid)
				->count();
			if ($check) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 余额 - 获取
	 * @param int $uid 代理ID
	 */
	public function get($uid = 0)
	{
		$balance = 0;
		if ($uid) {
			$where = "";
			$where = "main_id = " . $uid;
			$check = Db::name($this->config["balance"])
				->where($where)
				->count();
			if ($check) {
				$balance = Db::name($this->config["balance"])->where($where)->value("money");
			}
		}
		return $balance;
	}

	/**
	 * 综合【加、减】+ 日志
	 * 
	 * @param array $option 
	 *  传参规则
	 *	option = [
	 *		"aid"		=> "0", // 增 - 代理ID
	 * 		"sid"		=> "0"  // 减 - 代理ID
	 *		"typs"		=> "0", // 变更类型 1=分润,2=达标,3=流量卡,4=借款,5=还款,6=赠送,7=提现,8=认购 。。。。。。等
	 *		"isChg" 	=> "加_减", // 1 收入 2 支出 传 顺序 => 加_减[1_2]
	 *		"remark" 	=> "加-减",	// 备注  => 加减顺序 下划线 (_) 隔开 如：加_减
	 *		"chgAmt" 	=> "0",	// 变更金额
	 *		"ids" 		=> "0",	// 操作订单主ID ，注： 分润、达标、流量卡 传入产品ID
	 *	]
	 * @return boolean
	 */
	public function comp_and_log($option = [])
	{
		if (is_array($option) && !empty($option)) {
			// 参数验证
			if ($this->checkParams(
				$option,
				[
					"aid",
					"sid",
					"typs",
					"isChg",
					"chgAmt",
					"ids"
				]
			)) {
				// 减款代理余额
				$subBan = $this->get($option["sid"]);
				if (is_numeric($option['chgAmt']) && $subBan >= $option["chgAmt"]) {
					$exChg = explode("_", $option["isChg"]);
					$ckChg = true;
					foreach ($exChg as $v) {
						if (!in_array($v, $this->chgTyp)) {
							$ckChg = false;
							break;
						}
					}
					if ($ckChg) {
						$cords_temp = [];
						if (empty($option["remark"])) $option["remark"] = "加_减";
						$exRemark = explode("_", $option["remark"]);
						$cords_temp = [
							"uid" 	 => $option["aid"], 	// 收入 代理ID
							"isChg"	 => $exChg[0],			// 收入
							"remark" => $exRemark[0],		// 备注
							"chgAmt" => $option["chgAmt"],	// 变更金额
							"ids" 	 => $option["ids"],		// 订单主ID | 分润、达标、流量卡 传入产品ID
							"typs" 	 => $option["typs"], 	// 1=分润,2=达标,3=流量卡,4=借款,5=还款,6=赠送,7=提现,8=认购

						];
						$req = $this->add_and_logs($cords_temp);
						if ($req) {
							$cords_temp["uid"] = $option["sid"];  // 支出 代理ID
							$cords_temp["isChg"] = $exChg[1];	  // 支出
							$cords_temp["remark"] = $exRemark[1]; // 备注
							$reqSub = $this->sub_and_logs($cords_temp);
							if ($reqSub) {
								return true;
							}
						}
					}
				}
			}
		}
		return false;
	}

	/**
	 * 加 + 记录
	 * 
	 * @param array $option 
	 *  传参规则
	 *	option = [
	 *		"uid"		=> "0", // 收入 或 支出 代理ID
	 *		"typs"		=> "0", // 变更类型 1=分润,2=流量卡,3=达标,4=借款,5=还款,6=赠送,7=提现,8=认购,9=调价，10=采购
	 *		"isChg" 	=> "0", // 1 收入 
	 *		"remark" 	=> "x",	// 备注  => 没有备注传空字符串
	 *		"chgAmt" 	=> "0",	// 变更金额
	 *		"ids" 		=> "0",	// 操作订单主ID | 分润、达标、流量卡 传入产品ID
	 *	]
	 * @return int|boolean
	 */
	public function add_and_logs($option = [])
	{
		if (is_array($option)) {
			$check_prams = ["uid", "typs", "isChg", "chgAmt", "ids"];
			if ($this->checkParams($option, $check_prams)) {
				if (is_numeric($option["chgAmt"])) {
					$orig = $this->get($option["uid"]);
					$after = $option["chgAmt"];
					if ($orig > 0) {
						$after = $this->bcadds($orig, $after);
					}
					Db::startTrans();
					$flag = true;
					$reqAdd = $this->add($option["uid"], $option["chgAmt"]);
					if ($reqAdd) {
						$option["orig"] = $orig;
						$option["after"] = $after;
						$reqCords = $this->cords($option);
						if ($reqCords) {
							Db::commit();
							return true;
						} else {
							$flag = false;
						}
					}
					if ($flag === false) {
						Db::rollback();
					}
				}
			}
		}
		return false;
	}

	/**
	 * 加
	 * @param int $uid 代理ID
	 * @param float|string $money
	 * @return boolean
	 */
	public function add($uid = 0, $money = "")
	{
		if (!empty($uid)) {
			$data = [];
			$update = [];
			$check = $this->check($uid);
			if ($check) {
				$update["money"] = Db::raw("money" . " + " . $money);
				$update["total"] = Db::raw("total" . " + " . $money);
				$ret = Db::name($this->config["balance"])
					->where("main_id = " . $uid)
					->update($update);
				if ($ret) {
					return true;
				}
			} else {
				$data = ["main_type" => 2, "main_id" => $uid, "money" => $money, "total" => $money];
				$ret = Db::name($this->config["balance"])->insert($data);
				if ($ret) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 减 + 记录
	 * 
	 * @param array $option 
	 *  传参规则
	 *	option = [
	 *		"uid"		=> "0", // 收入 或 支出 代理ID
	 *		"typs"		=> "0", // 变更类型 1=分润,2=达标,3=流量卡,4=借款,5=还款,6=赠送,7=提现,8=认购 。。。。。。
	 *		"isChg" 	=> "0", // 2 支出
	 *		"remark" 	=> "x",	// 备注  => 没有备注传空字符串
	 *		"chgAmt" 	=> "0",	// 变更金额
	 *		"ids" 		=> "0",	// 操作订单主ID | 分润、达标、流量卡 传入产品ID
	 *	]
	 * @return int|boolean
	 */
	public function sub_and_logs($option = [])
	{
		if (is_array($option)) {
			$check_prams = ["uid", "typs", "isChg", "chgAmt", "ids"];
			if ($this->checkParams($option, $check_prams)) {
				$orig = $this->get($option["uid"]);
				if (is_numeric($option["chgAmt"]) && $orig >= $option["chgAmt"]) {
					$after = $option["chgAmt"];
					if ($orig > 0) {
						$after = $this->bcsubs($orig, $after);
					}
					Db::startTrans();
					$flag = true;
					$reqSub = $this->sub($option["uid"], $option["chgAmt"]);
					if ($reqSub) {
						$option["orig"] = $orig;
						$option["after"] = $after;
						$reqCords = $this->cords($option);
						if ($reqCords) {
							Db::commit();
							return true;
						} else {
							$flag = false;
						}
					}
					if ($flag === false) {
						Db::rollback();
					}
				}
			}
		}
		return false;
	}

	/**
	 * 减
	 * @param int $uid 代理ID
	 * @param float|string $money
	 * @return boolean
	 */
	public function sub($uid = 0, $money = "")
	{
		if (!empty($uid)) {
			$update = [];
			$check = $this->check($uid);
			if ($check) {
				$update["money"] = Db::raw("money" . " - " . $money);
				$ret = Db::name($this->config["balance"])->where("main_id = " . $uid)->update($update);
				if ($ret) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 *  余额变更记录
	 *  传参规则
	 *	option = [
	 *		"uid"		=> "0", // 收入 或 支出 代理ID
	 *		"typs"		=> "0", // 变更类型 1=分润,2=达标,3=流量卡,4=借款,5=还款,6=赠送,7=提现,8=认购 。。。。。。
	 *		"isChg" 	=> "0", // 1 收入 2 支出
	 *		"remark" 	=> "x",	// 备注  => 没有备注传空字符串
	 *		"orig"		=> "0", // 原余额    => 默认传0
	 *		"chgAmt" 	=> "0",	// 变更金额
	 *		"after"		=> "0"  // 变更后余额
	 *		"ids" 		=> "0",	// 操作订单主ID | 分润、达标、流量卡、调价 传入产品ID
	 * 		"sn"		=> ""	// 终端号
	 *  	"times"		=> "" 	// 时间 -> 传时间戳  、格式[YY-mm-dd H:i:s]
	 *	]
	 * @return int|boolean
	 */
	public function cords($option = [])
	{
		if (is_array($option) && !empty($option)) {
			$table = "";
			$store_arr = [];
			$check_prams = ["uid", "typs", "isChg", "chgAmt", "ids"];
			if ($this->checkParams($option, $check_prams)) {
				$store_arr = [
					"main_id" 			=> $option["uid"], 		// 收入 或 支出 代理ID
					"balance_type_id" 	=> $option["typs"], 	// 变更类型 1=分润,2=达标,3=流量卡,4=借款,5=还款,6=赠送,7=提现,8=认购 
					"earn_type"			=> $option["isChg"],	// 1 收入 2 支出
					"mome" 				=> $option["remark"],	// 备注
					"before" 			=> $option["orig"],		// 变更金额
					"after" 			=> $option["after"],	// 变更后余额
					"money" 			=> $option["chgAmt"],	// 变更金额
					"product_id" 		=> $option["ids"],		// 操作订单主ID | 分润、达标、流量卡、调价 传入产品ID
					"times"				=> strtotime(date("Y-m-d"), time()),
					"create_time" 		=> time(),
				];
				if (isset($option["times"])) {
					$store_arr["times"] = strtotime(date("Y-m-d", $option["times"]));
					$store_arr["create_time"] = $option["times"];
				}
				if (isset($option["sn"])) {
					$store_arr["sn"] = $option["sn"];
				}
				// $table = \app\common\func\Tables::instance()->balance_log();
				$id = Db::name($this->config["log"])->insertGetId($store_arr);
				if ($id) {
					$this->change_day_log($store_arr["main_id"], $store_arr["earn_type"], $store_arr["money"], $store_arr["times"], $store_arr["balance_type_id"]);
					return $id;
				}
			}
		}
		return false;
	}

	/**
	 * 按天变更 - 日志
	 */
	public function change_day_log($uid, $isChg, $money, $times, $typs)
	{
		try {
			if (!empty($uid) && !empty($isChg) && !empty($money) && !empty($times)) {
				$option = [];
				$nowTimes = strtotime(date("Y-m-d", time()));
				$option = ["uid" => $uid, "times" => $times];
				$nums_field = ($isChg == 1 ? "in_nums" : ($isChg == 2 ? "ex_nums" : ""));
				$money_field = ($isChg == 1 ? "income" : ($isChg == 2 ? "expend" : ""));
				if (!empty($nums_field) || !empty($money_field)) {
					$after = $this->_get_after_balance($uid, $times);
					$chang = 0;
					switch ($isChg) {
						case 1:
							$chang = $this->bcadds($after, $money);
							break;
						case 2:
							$chang = $this->bcsubs($after, $money);
							break;
					}
					if (in_array($typs, $this->typsArr)) {
						if ($times < $nowTimes) {
							$this->update_last_log($uid, $times, $money);
						}
					}
					$check_store_days = Db::name($this->config["day_log"])->where($option)->count();
					if ($check_store_days) {
						$update = [];
						$update[$nums_field] = Db::raw($nums_field . " + 1");
						$update[$money_field] = Db::raw($money_field . " + " . $money);
						$update["afters"] = $chang;
						Db::name($this->config["day_log"])->where($option)->update($update);
					} else {
						$option[$nums_field] = 1;
						$option[$money_field] = $money;
						$option["orig"] = $after;
						$option["afters"] = $chang;
						Db::name($this->config["day_log"])->insert($option);
					}
				}
			}
		} catch (\Exception $e) {
			Log::write($e->getMessage());
		}
	}

	/**
	 * 更新
	 */
	public function update_last_log($uid, $times, $money)
	{
		try {
			$where = "uid = {$uid} and times > {$times}";
			$check = Db::name($this->config["day_log"])
				->where($where)
				->count();
			if ($check) {
				$query = Db::name($this->config["day_log"])
					->where($where)
					->field("id")
					->order("times ASC")
					->select();
				foreach ($query as $vals) {
					$update = [];
					$update["orig"] = Db::raw("orig + " . $money);
					$update["afters"] = Db::raw("afters + " . $money);
					Db::name($this->config["day_log"])->where("id = " . $vals["id"])->update($update);
				}
			}
		} catch (\Exception $e) {
			Log::write($e->getMessage());
		}
	}

	/**
	 * 获取 - 变更后余额
	 */
	public function _get_after_balance($uid, $times)
	{
		$return = 0;
		$current = "";
		$before = "";
		if (!empty($uid) && !empty($times)) {
			$current = $times;
			$before = strtotime("-1 day", $current);
			$where = ["uid" => $uid, "times" => $current];
			$check_current_days = Db::name($this->config["day_log"])
				->where($where)
				->count();
			if ($check_current_days) {
				$return = Db::name($this->config["day_log"])
					->where($where)
					->value("afters");
			} else {
				// $where["times"] = $before;
				$check_before_days = Db::name($this->config["day_log"])
					->where("uid = {$uid} and times <= " . $before)
					->count();
				if ($check_before_days) {
					$return = Db::name($this->config["day_log"])
						->where("uid = {$uid} and times <= " . $before)
						->order("times DESC")
						->value("afters");
				}
			}
		}
		return $return;
	}

	/**
	 * 减
	 */
	protected function bcsubs($nums = 0, $twos = 0)
	{
		return bcsub((string) $nums, (string)$twos, 2);
	}

	/**
	 * 加
	 */
	protected function bcadds($nums = 0, $twos = 0)
	{
		return bcadd((string) $nums, (string)$twos, 2);
	}

	/**
	 * 检测元素是否正确
	 * 只能检测一维数组
	 * @param $arr 被检测的数组
	 * @param $repar $arr中必要的元素(键名)
	 * @return boolean
	 */
	protected function checkParams($arr, $repar = array())
	{
		if (!is_array($arr)) {
			return false;
		}
		if (!count($arr)) {
			return false;
		}
		// 判断每个元素是否存在
		if (count($repar)) {
			foreach ($repar as $val) {
				if (!in_array($val, array_keys($arr))) {
					return false;
					break;
				}
			}
		}
		// 判断每个元素的值是否正确
		foreach ($arr as $key => $val) {
			if (in_array($key, $repar)) {
				if ($val == "" || $val == false || $val == null || $val == "undefined" || $val == "null" || $val == 0) {
					return false;
					break;
				}
			}
		}
		return true;
	}
}
